package com.gitee.wsl.collections.trie

import com.gitee.wsl.base.Objects
import com.gitee.wsl.base.Objects.equals
import com.gitee.wsl.collections.iterator.api.MutableMapEntry
import com.gitee.wsl.collections.map.api.SequencedMap
import com.gitee.wsl.collections.trie.analyzer.KeyAnalyzer
import com.gitee.wsl.collections.trie.api.Trie
import kotlin.collections.Map.Entry


/**
 * This class provides some basic [Trie] functionality and
 * utility methods for actual bitwise [Trie] implementations.
 *
 * @param <K> the type of the keys in this map
 * @param <V> the type of the values in this map
 * @since 4.0
</V></K> */
abstract class AbstractBitwiseTrie<K, V> protected constructor(
    val keyAnalyzer: KeyAnalyzer<K>
) : AbstractMutableMap<K, V>(), Trie<K, V> {
    
    /**
     * A basic implementation of [Entry].
     *
     * @param <K> the type of the keys in this entry.
     * @param <V> the type of the values in this entry.
    </V></K> */
    abstract class BasicEntry<K, V>(
        /**
         * The entry's key.
         */
        override var key: K,
        /**
         * The entry's value.
         */
        override var value: V
    ) : MutableMapEntry<K, V> {


        override fun equals(o: Any?): Boolean {
            if (o === this) {
                return true
            }
            if (o !is BasicEntry<*, *>) {
                return false
            }

            val other = o as BasicEntry<K, V>
            if (compare(key, other.key)
                && compare(value, other.value)
            ) {
                return true
            }
            return false
        }

        override fun hashCode(): Int {
            return (if (this.key == null) 0 else this.key.hashCode()) xor
                    (if (this.value == null) 0 else this.value.hashCode())
        }

        /**
         * Replaces the current key and value with the provided key &amp; value.
         *
         * @param key The new key.
         * @param value The new value.
         * @return The previous value.
         */
        fun setKeyValue(key: K, value: V): V {
            this.key = key
            return setValue(value)
        }

        override fun setValue(newValue: V): V {
            val previous = this.value
            this.value = newValue
            return previous
        }

        override fun toString(): String {
            return "$key=$value"
        }

    }

    /**
     * The [KeyAnalyzer] that's being used to build the PATRICIA [Trie].
     */
     //val keyAnalyzer: KeyAnalyzer<in K> = Objects.requireNonNull(keyAnalyzer, "keyAnalyzer")

    /**
     * Utility method for calling [KeyAnalyzer.bitIndex].
     */
    fun bitIndex(key: K, foundKey: K): Int {
        return keyAnalyzer.bitIndex(key, 0, lengthInBits(key), foundKey, 0, lengthInBits(foundKey))
    }

    /**
     * Returns the number of bits per element in the key
     *
     * @see KeyAnalyzer.bitsPerElement
     */
    fun bitsPerElement(): Int {
        return keyAnalyzer.bitsPerElement()
    }

    /**
     * A utility method to cast keys. It actually doesn't cast anything. It's just fooling the compiler!
     */
//    fun castKey(key: Any?): K? {
//        return key as K?
//    }

    /**
     * A utility method for calling [KeyAnalyzer.compare]
     */
    fun compareKeys(key: K?, other: K?): Boolean {
        if (key == null) {
            return other == null
        }
        if (other == null) {
            return false
        }

        return keyAnalyzer.compare(key, other) == 0
    }

    override fun reversed(): SequencedMap<K, V> {
        TODO("Not yet implemented")
    }

    /**
     * Returns the [KeyAnalyzer] that constructed the [Trie].
     * @return the [KeyAnalyzer] used by this [Trie]
     */
//    protected fun getKeyAnalyzer(): KeyAnalyzer<in K> {
//        return keyAnalyzer
//    }

    /**
     * Returns whether or not the given bit on the key is set or false if the key is null.
     *
     * @see KeyAnalyzer.isBitSet
     */
    fun isBitSet(key: K?, bitIndex: Int, lengthInBits: Int): Boolean {
        if (key == null) { // root's might be null!
            return false
        }
        return keyAnalyzer.isBitSet(key, bitIndex, lengthInBits)
    }

    /**
     * Returns the length of the given key in bits
     *
     * @see KeyAnalyzer.lengthInBits
     */
    fun lengthInBits(key: K?): Int {
        if (key == null) {
            return 0
        }

        return keyAnalyzer.lengthInBits(key)
    }

    override fun toString(): String {
        val buffer = StringBuilder()
        buffer.append("Trie[").append(size).append("]={\n")
        for (entry in entries) {
            buffer.append("  ").append(entry).append("\n")
        }
        buffer.append("}\n")
        return buffer.toString()
    }

    companion object {

        /**
         * Delegates to [Objects.equals].
         */
        fun compare(a: Any?, b: Any?): Boolean {
            return equals<Any?>(a, b)
        }
    }
}
